package com.orangecy.common.log;

import com.alibaba.fastjson.JSON;
import lombok.Data;

import java.util.LinkedHashMap;
import java.util.Objects;

/**
 * @Author : orangeCy.奕
 * @Product : 猎豹养成产品源码
 * @Time : 2021/10/23
 * @Desc : 日志承载
 */
@Data
public class OrangeCyLog {
    private static final String START = "<<<";
    private static final String END = ">>>";
    private static final String SPLIT_LEFT = "【";
    private static final String SPLIT_RIGHT = "】";

    /**
     * 提取pKey 作为参数域容器{paramsMap}的key
     */
    private static final String P_KEY = "pKey";
    /**
     * 提取cKey 作为参数域容器{contextMap}的key
     */
    private static final String C_KEY = "cKey";

    /**
     * 参数域容器
     */
    private LinkedHashMap<String,Object> paramsMap;
    /**
     * 过程变量域容器
     */
    private LinkedHashMap<String,Object> contextMap;
    /**
     * 返回值信息
     */
    private Object returnVal;
    /**
     * 描述
     */
    private String desc;

    public OrangeCyLog(String desc) {
        this.paramsMap = new LinkedHashMap<>();
        this.contextMap = new LinkedHashMap<>();
        this.desc = desc;
    }

    /**
     * 顺序的p方法 控制顺序
     */
    public HalfComplete pKey(String pKey) {
        return new HalfComplete(pKey,this,P_KEY);
    }

    /**
     * 顺序的c方法 控制顺序
     */
    public HalfComplete cKey(String cKey) {
        return new HalfComplete(cKey, this, C_KEY);
    }

    class HalfComplete{
        private OrangeCyLog parent;
        private String pKey;
        private String cKey;
        private String flag;

        public OrangeCyLog value(String value) {
            if(P_KEY.equals(flag)) {
                parent.paramsMap.put(this.pKey,value);
                return parent;
            }
            parent.contextMap.put(this.cKey,value);
            return parent;
        }

        HalfComplete(String key, OrangeCyLog parent, String flag){
            if(P_KEY.equals(flag)) {
                this.pKey = key;
            }else {
                this.cKey = key;
            }
            this.parent = parent;
            this.flag = flag;
        }
    }

    /**
     *
     * @param desc
     * @return
     */
    public static OrangeCyLog desc(String desc) {
        return new OrangeCyLog(desc);
    }

    /**
     * 这里可能多次记录 不一定在一个类中 将日志的初始化 构建 以及终结 解开
     * @param logData
     * @param returnVal
     */
    public static void setRetValue(OrangeCyLog logData,Object returnVal) {
        if(Objects.nonNull(logData)) {
            logData.setReturnVal(returnVal);
        }
    }

    @Override
    public String toString(){
        return new StringBuilder().append(START)
                .append(SPLIT_LEFT)
                .append("日志描述:")
                .append(desc)
                .append(SPLIT_RIGHT)
                .append(SPLIT_LEFT)
                .append("入参容器:")
                .append(JSON.toJSONString(paramsMap))
                .append(SPLIT_RIGHT)
                .append(SPLIT_LEFT)
                .append("过程变量:")
                .append(JSON.toJSONString(contextMap))
                .append(SPLIT_RIGHT)
                .append(SPLIT_LEFT)
                .append("返回值")
                .append(JSON.toJSONString(returnVal))
                .append(SPLIT_RIGHT).append(END).toString();
    }

    public static void main(String[] args) {
        /**
         * 严格控制创建实例对象 先访问P或者C方法 再访问V方法 最终执行终结操作
         * 此思路 是采用Lambda思想 其源码给了启发 分享大家
         */
        //LogData.desc("xx").value();会报错的 先执行value不行
        //LogData.desc("xx").pKey("pKey").pKey("pKey"); 会报错的 连续执行p 或者连续执行v不行
        OrangeCyLog createItemLog = OrangeCyLog.desc("创建商品").pKey("itemId").value("123")
                .pKey("picture").value("img://a.jpg")
                //过程变量 比如你在创建商品流程中 调用了一个PRC接口，你可以记录返回值需要关心的字段在过程变量中
                //假设是调用风控服务，查看此标题是否合适，返回true/false 那么可以打印在日志里
                .cKey("riskRet").value("true")
                .cKey("stockNum").value("99");
        createItemLog.setReturnVal("invoke success");
        System.out.println(createItemLog.toString());
    }
}